package file;

import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.ArrayList;
import java.util.List;

/**
 * 游戏主面板
 */
public class Game extends JPanel {
    // 贪吃蛇链
    private List<Point> snake;
    // 分数
    private List<Point> foods;
    // 操作枚举
    private enumHandle handle = enumHandle.RIGHT;
    private enum enumHandle {UP, DOWN, LEFT, RIGHT};
    // 状态枚举
    private enumStatus status = enumStatus.WAIT;
    private enum enumStatus {WAIT, PLAYING, DEAD};
    // 分数
    private int gameScore; //游戏分数
    // 边界
    private final int BORDER_MIN_X = 0;
    private final int BORDER_MAX_X = 30;
    private final int BORDER_MIN_Y = 0;
    private final int BORDER_MAX_Y = 30;

    /**
     * 游戏初始化
     */
    public Game() {
        // 对象初始化
        init();
        // 键盘监听
        this.setFocusable(true); // 确保焦点在游戏上
        this.addMyKeyListener();
        System.out.println("Game");
    }
    /**
     * 初始化对象
     */
    private void init(){
        gameScore = 0; // 初始化游戏分数
        // 初始化蛇
        snake = new ArrayList<Point>();
        snake.add(new Point(Point.header,15,15));
        snake.add(new Point(Point.body,14,15));
        // 放置分数
        foods = new ArrayList<Point>();
        foods.add(new Point(Point.score,5,25));
        foods.add(new Point(Point.score,26,10));
        foods.add(new Point(Point.score,10,10));
        foods.add(new Point(Point.score,20,20));
        foods.add(new Point(Point.score,24,15));
    }

    /**
     * 图层面板
     */
    @Override
    protected void paintComponent(Graphics g) {
//        System.out.println("画面刷新");
        super.paintComponent(g); // 清屏
        this.setBackground(Color.white); // 背景白屏
        g.fillRect(7, 47, 480, 480); // 黑色背景 16 * 16 * 30(单元格单位16)

        // 分数
        g.drawString("分数 :" + gameScore,7,20);
        // 开始提示
        if (status==enumStatus.WAIT){
            // 游戏提示
            g.setColor(Color.white);
            g.setFont(new Font("微软雅黑",Font.BOLD,40));
            g.drawString("按下空格开始游戏!",100,300);
        }else if (status==enumStatus.DEAD){
            g.setColor(Color.RED);
            g.setFont(new Font("微软雅黑",Font.BOLD,40));
            g.drawString("失败, 按下空格重新开始",50,300);
        }

        // 食物绘制
        for (int i = 0; i < foods.size(); i++) {
            foods.get(i).showPoint(this, g);
        }
        // 根据画面状态变化
        if(status == enumStatus.PLAYING){
            // 运行中
            changeSnake(g);
        }
    }

    /**
     * 显示蛇部分
     */
    private void changeSnake(Graphics g){
        // 移动变化
         if(null != handle){
            // 头部变化
            Point first = snake.get(0);
            int newFirstX = first.getX();
            int newFirstY = first.getY();
            switch (handle){
                case LEFT: newFirstX-=1;break;
                case RIGHT: newFirstX+=1;break;
                case UP: newFirstY-=1;break;
                case DOWN: newFirstY+=1;break;
                default:;
            }

            // 判断头部是否和分数重复
            Point newPoint = null;
            for (int i = 0; i < foods.size(); i++) {
                if(foods.get(i).isOver(newFirstX, newFirstY)){
                    // 重复，说明吃掉了对象
                    // 追加末尾对象
                    newPoint = new Point(Point.body, snake.get(snake.size() - 1).getX(), snake.get(snake.size() - 1).getY());
                    // 删除
                    foods.remove(i);
                    break;
                }
            }
            // 循环变化
            for (int i = snake.size() - 1; i >= 1; i--) {
                snake.get(i).setPoint(snake.get(i-1).getX(), snake.get(i-1).getY());
            }
            // 末尾追加
            if(null != newPoint){
                snake.add(newPoint);
                gameScore++;
            }
            // 最后头部变化
            first.setPoint(newFirstX, newFirstY);

             // 死亡判断 - 边界
             if(newFirstX < BORDER_MIN_X || newFirstY < BORDER_MIN_Y || newFirstX > BORDER_MAX_X || newFirstY > BORDER_MAX_Y){
                 System.out.println("死亡判断 - 边界");
                 status = enumStatus.DEAD;
                 repaint(); // 【页面刷新】
             }
             // 死亡判断 - 碰触自身
             for (int i = 1; i < snake.size(); i++) {
                 if(snake.get(i).isOver(first)){
                     System.out.println("死亡判断 - 碰触自身");
                     status = enumStatus.DEAD;
                     repaint(); // 【页面刷新】
                 }
             }
        }
        // 设绘制
        for (int i = snake.size() - 1; i >= 0; i--) {
            snake.get(i).showPoint(this, g);
        }
        // 间隔刷新
        try {
            Thread.sleep(200);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        repaint(); // 【页面刷新】
    }

    /**
     * 追加键盘监听
     */
    private void addMyKeyListener(){
        // 追加键盘监听
        this.addKeyListener(new KeyListener() {
            @Override
            public void keyTyped(KeyEvent e) {
            }
            @Override
            public void keyPressed(KeyEvent e) { // 对应键盘按下时反应

                if(status == enumStatus.PLAYING){
                    // 移动键盘
                    switch (e.getKeyCode()){
                        case KeyEvent.VK_LEFT: if(handle != enumHandle.RIGHT) {handle = enumHandle.LEFT;}break;
                        case KeyEvent.VK_RIGHT: if(handle != enumHandle.LEFT) {handle = enumHandle.RIGHT;}break;
                        case KeyEvent.VK_UP: if(handle != enumHandle.DOWN) {handle = enumHandle.UP;}break;
                        case KeyEvent.VK_DOWN: if(handle != enumHandle.UP) {handle = enumHandle.DOWN;}break;
                        default:handle = null;
                    }
                }else {
                    // 空格重启状态
                    if (e.getKeyCode() == KeyEvent.VK_SPACE){
                        status = enumStatus.PLAYING;
                        // 初始化
                        init();
                    }
                }
                repaint(); // 【页面刷新】
            }
            @Override
            public void keyReleased(KeyEvent e) {
            }
        });
    }
}
